#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>
#include <unistd.h>

#include "serial.h"
#include "wifi_parse.h"

int fd;

const static wifi_cmd_t wifi_cmds[WIFI_CMD_NUM] = {
    {"AT+",         300,    300},
    {"AT+E",        300,    300},
    {"AT+ENTM",     300,    300},
    {"AT+NETP",     300,    300},
    {"AT+UART",     300,    300},
    {"AT+UARTF",    300,    300},
    {"AT+UARTFT",   300,    300},
    {"AT+UARTFL",   300,    300},
    {"AT+TMODE",    300,    300},
    {"AT+WMODE",    300,    300},
    {"AT+WSKEY",    300,    300},
    {"AT+WSSSID",   300,    300},
    {"AT+WSLK",     300,    300},
    {"AT+WEBU",     300,    300},
    {"AT+WAP",      300,    300},
    {"AT+WAKEY",    300,    300},
    {"AT+HIDESSID", 300,    300},
    {"AT+MSLP",     300,    300},
//  {"AT+WSCAN",    3000,   3000},
    {"AT+TCPLK",    300,    300},
    {"AT+TCPDIS",   300,    300},
    {"AT+WANN",     300,    300},
    {"AT+LANN",     300,    300},
    {"AT+DHCPDEN",  300,    300},
    {"AT+DHCPGW",   300,    300},
    {"AT+TCPTO",    300,    300},
    {"AT+MAXSK",    300,    300},
    {"AT+TCPB",     300,    300},
    {"AT+TCPPTB",   300,    300},
    {"AT+TCPADDB",  300,    300},
    {"AT+TCPTOP",   300,    300},
    {"AT+TCPLKB",   300,    300},
    {"AT+EPHY",     300,    300},
    {"AT+STTC",     300,    300},
    {"AT+DOMAIN",   300,    300},
    {"AT+FRLDEN",   300,    3000},
    {"AT+RELD",     300,    300},
    {"AT+Z",        300,    300},
    {"AT+MID",      300,    300},
    {"AT+WRMID",    300,    300},
    {"AT+VER",      300,    300},
//  {"AT+H",        300,    300},
    {"AT+FVEW",     300,    300},
    {"AT+FVER",     300,    300},
    {"AT+WMAC",     300,    300},
    {"AT+PING",     300,    300},
    {"AT+FEPHY",    300,    5000},
};

int wifi_init(void)
{
    char tmp[WIFI_STRING_MAX_SIZE] = {0};

    tcflush(fd, TCIFLUSH); // clear data received but not read

    serial_write(fd, "\n\n\n", 3); // clear send cache
    usleep(100000);
    if (serial_write(fd, "+++", 3) == 3)
    usleep(300000);
    if (serial_read(fd, tmp, WIFI_STRING_MAX_SIZE) > 0)
    {
        if (strstr(tmp, "a") != NULL)
        {
            serial_write(fd, "a", 1);
            usleep(300000);
            if (serial_read(fd, tmp, WIFI_STRING_MAX_SIZE) > 0
                    && strstr(tmp, WIFI_RET_SUCCESS) != NULL)
            {
                return 0;
            }
        }
    }

    return -1;
}

int wifi_at_test(void)
{
    char tmp[WIFI_STRING_MAX_SIZE] = {0};

    wifi_at_get(WIFI_CMD_AT, tmp);
    if (wifi_at_get(WIFI_CMD_AT, tmp) == 0)
        return 0;

    return -1;
}

int wifi_at_get(wifi_cmd_e cmd, char *ret)
{
    int i;
    char tmp[WIFI_STRING_MAX_SIZE] = {0}, *ptmp;
    int readlen = 0, totallen = 0;
    int begin = 0, again = 0;

    if (!ret)
        return -1;

    tcflush(fd, TCIFLUSH); // clear data received but not read

    sprintf(tmp, "%s\n", wifi_cmds[cmd].cmd);
    serial_write(fd, tmp, strlen(tmp));
    for (i = 0; i < wifi_cmds[cmd].r_wait / WIFI_PARSE_LOOP_TIME; i++)
    {
        usleep(WIFI_PARSE_LOOP_TIME * 1000);
        if ((readlen = serial_read(fd, tmp + totallen, WIFI_STRING_MAX_SIZE - totallen)) <= 0)
        {
            again++;
            if (begin && again >= wifi_cmds[cmd].r_wait / WIFI_PARSE_LOOP_TIME) // no continuous data
                break;
        } else {
            begin++;
            totallen += readlen;
        }
    }
    tmp[totallen] = '\0'; // add the string end

    // parse
    if (totallen)
    {
        if ((ptmp = strstr(tmp, WIFI_RET_SUCCESS)) != NULL)
        {
            if ((ptmp = strstr(tmp, WIFI_RETDATA_SUCCESS)) != NULL)
            {
                strncpy(ret, ptmp + strlen(WIFI_RETDATA_SUCCESS), WIFI_STRING_MAX_SIZE);
            } else {
                ret = NULL;
            }

            return 0;
        }
        if ((ptmp = strstr(tmp, WIFI_RET_FAIL)) != NULL)
        {
            if ((ptmp = strstr(tmp, WIFI_RETDATA_FAIL)) != NULL)
            {
                strncpy(ret, ptmp + strlen(WIFI_RETDATA_SUCCESS), WIFI_STRING_MAX_SIZE);
            } else {
                ret = NULL;
            }

            return -1;
        }
    } 

    ret = NULL;
    
    return -1;
}

int wifi_at_set(wifi_cmd_e cmd, const char *value, char *ret)
{
    int i;
    char tmp[WIFI_STRING_MAX_SIZE] = {0}, *ptmp;
    int readlen = 0, totallen = 0;
    int begin = 0, again = 0;

    if (!value || !ret)
        return -1;

    tcflush(fd, TCIFLUSH); // clear data received but not read

    sprintf(tmp, "%s=%s\n", wifi_cmds[cmd].cmd, value);
    serial_write(fd, tmp, strlen(tmp));

    for (i = 0; i < wifi_cmds[cmd].w_wait / WIFI_PARSE_LOOP_TIME; i++)
    {
        usleep(WIFI_PARSE_LOOP_TIME * 1000);
        if ((readlen = serial_read(fd, tmp + totallen, WIFI_STRING_MAX_SIZE - totallen)) <= 0)
        {
            again++;
            if (begin && again >= wifi_cmds[cmd].w_wait / WIFI_PARSE_LOOP_TIME) // no continuous data
                break;
        } else {
            begin++;
            totallen += readlen;
        }
    }
    tmp[totallen] = '\0'; // add the string end

    // parse
    if (totallen)
    {
        if ((ptmp = strstr(tmp, WIFI_RET_SUCCESS)) != NULL)
        {
            if ((ptmp = strstr(tmp, WIFI_RETDATA_SUCCESS)) != NULL)
            {
                strncpy(ret, ptmp + strlen(WIFI_RETDATA_SUCCESS), WIFI_STRING_MAX_SIZE);
            } else {
                ret = NULL;
            }

            return 0;
        }
        if ((ptmp = strstr(tmp, WIFI_RET_FAIL)) != NULL)
        {
            if ((ptmp = strstr(tmp, WIFI_RETDATA_FAIL)) != NULL)
            {
                strncpy(ret, ptmp + strlen(WIFI_RETDATA_FAIL), WIFI_STRING_MAX_SIZE);
            } else {
                ret = NULL;
            }

            return -1;
        }
    } 
    
    ret = NULL;
    
    return -1;
}

int main(int argc, char *argv[])
{
    char tmp[WIFI_STRING_MAX_SIZE] = {0};

    if (argc < 2)
        return -1;

    if ((fd = serial_open(argv[1], 57600, 'N', 8, 1, 0, 0)) > 0)
    {
        if (wifi_at_test() != 0)
        {
            printf("not enter the at mode, start init!\n");
            if (wifi_init())
            {
                printf("enter at mode failed!\n");

                return -1;
            }
            // close echo
            wifi_at_get(WIFI_CMD_E, tmp);
        }
        printf("enter AT mode...\n");

        if (!wifi_at_get(WIFI_CMD_FEPHY, tmp))
        {
            if (strncmp(tmp, "off", 3) == 0)
            {
                // enter phy interface
                if (wifi_at_set(WIFI_CMD_FEPHY, "on", tmp) == 0)
                {
                    printf("enable EPHY successful!\n");
                } else {
                    printf("enable EPHY failed!\n");
                }
            } else {
            printf("EPHY default value is 'on'\n");
            }
        } else {
            printf("get FEPHY value failed!\n");
        }

        // exit AT mode
        printf("exit AT mode...\n");
        wifi_at_get(WIFI_CMD_ENTM, tmp);
    }

    return 0;
}

